﻿using Hydrogen.ULib.Attributes;
using Hydrogen.ULib.Logger;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Hydrogen.MarkovChain.SolidMap2DScene
{
    public enum DriveStatus
    {
        /// <summary>
        /// 未开启/已结束
        /// </summary>
        Stoped = 0,
        /// <summary>
        /// 进行中
        /// </summary>
        Running = 1,
        /// <summary>
        /// 暂停
        /// </summary>
        Paused = 2,
    }

    /// <summary>
    /// 驱动马尔科夫链进行下去
    /// </summary>
    public class Driver : MonoBehaviour
    {
        private SolidMap2dResManager _resMgr;
        private Interpreter _interpreter;
        private Map _map;

        public bool IsInited { get; private set; }

        public float StepDuration
        {
            get => this._stepDuration;
            set
            {
                this._stepDuration = Mathf.Max(value, 0.05f);
            }
        }
        [SerializeField, Range(0.01f, 0.25f)]
        private float _stepDuration = 0.1f;

        /// <summary>
        /// 驱动器的状态
        /// </summary>
        public DriveStatus Status
        {
            get => this._status;
            set => this._status = value;
        }
        [SerializeField, ReadOnly]
        private DriveStatus _status;

        private Coroutine _runCoro;

        public void Init(SolidMap2dResManager resMgr, Map map, string ruleName)
        {
            IsInited = false;
            this._resMgr = resMgr;
            this._map = map;

            this._interpreter = new Interpreter(this._resMgr, SolidMap2dResConstant.GetRuleAddr(ruleName));
            this._interpreter.Init();

            if (!this._interpreter.IsInited) return;
            if (this._resMgr == null || this._map == null) return;
            IsInited = true;
        }

        public void StartRun()
        {
            if (this._runCoro != null) StopCoroutine(this._runCoro);
            if (!IsInited) return;


            this._runCoro = StartCoroutine(Run());
        }

        private void ResetDrive()
        {
            this._map?.ResetMap();

            //RuleSP sp;
            //if (this._interpreter.SP.Count > 0)
            //    sp = this._interpreter.SP[0];
            //else sp = new RuleSP();

            //this._map?.SetSP(sp);
            foreach (var item in this._interpreter.SP)
            {
                this._map?.SetSP(item);
            }
        }

        private IEnumerator Run()
        {
            ResetDrive();

            yield return null;
            LoggerManager.LogYellowFlag("Driver 开始");
            Status = DriveStatus.Running;

            //Vector2Int curr = sp.Pos.ConvertV2();
            List<SolidType> outTypes = new List<SolidType>();
            Direction dir = Direction.D;

            List<Direction> dirs = new List<Direction>()
            { Direction.U, Direction.D, Direction.L, Direction.R };
            List<Direction> check = new List<Direction>();

            Func<IRuleNodeSolidReplace, bool> filter = this._map.TryExcute;
            //{
            //    Utils.RandomArray(dirs);
            //    foreach (var item in dirs)
            //    {
            //        check.Clear();
            //        for (var i = 0; i < inTypes.Count - 1; i++) check.Add(item);
            //        if (this._map.Match(curr, inTypes, check))
            //        {
            //            dir = item;
            //            return true;
            //        }
            //    }
            //    return false;
            //};

            this._interpreter.Reset();
            while (this._interpreter.TryExcute(filter))
            {
                yield return new WaitForSeconds(this.StepDuration);
            }

            LoggerManager.LogYellowFlag("Driver 结束");
            Status = DriveStatus.Stoped;
        }
    }
}